package chen.web.controller.forum;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import chen.web.controller.blog.form.SignupForm;
import chen.web.controller.forum.form.AccountInfoForm;
import chen.web.controller.forum.form.ChangePasswordForm;
import chen.web.user.Account;
import chen.web.user.AccountManager;
import chen.web.user.EmailAlreadyBeenRegisteredException;
import chen.web.user.ExtInfo;
import chen.web.user.InvalidPasswordException;
import chen.web.user.NicknameAlreadyBeenRegisteredException;
import chen.web.util.ImageResize;
import chen.web.util.PathUtil;
import chen.web.util.UnsupportImageTypeException;


public class AccountController {
	
	private Validator validator;
	private AccountManager am;
	
	@Autowired
	public AccountController(AccountManager am, Validator validator) {
		this.validator = validator;
		this.am = am;
	}
	//更改帐号信息
	@RequestMapping(value="/account/{id}", method=RequestMethod.PUT)
	public @ResponseBody JSONResponse updateInfo(@RequestBody AccountInfoForm bean, @PathVariable int id){
		Set<ConstraintViolation<AccountInfoForm>> failures = validator.validate(bean);
		if(!failures.isEmpty()){
			return JSONResponse.invalid(failures);
		}
		
		Account acc = am.getAccount(id);
		ExtInfo info = acc.getExtInfo();
		info.setBirthday(bean.getBirthday());
		info.setCityId(bean.getCity());
		info.setFactory(bean.getFactory());
		info.setIntro(bean.getIntro());
		info.setProvinceId(bean.getProvince());
		info.setResidenceId(bean.getResidence());
		info.setSex(bean.getSex());
		info.setSignature(bean.getSignature());
		info.setQq(bean.getQq());
		am.update(acc);
		return JSONResponse.successed();
	}
	
	@RequestMapping(value="/signup", method=RequestMethod.POST)
	public @ResponseBody JSONResponse signUp(@RequestBody SignupForm bean){
		Set<ConstraintViolation<SignupForm>> failures = validator.validate(bean);
		if (!failures.isEmpty()) {
			return JSONResponse.invalid(failures);
		} 
		
		JSONResponse res = JSONResponse.successed();
		try {
			Account account = am.register(bean.getNickname(), bean.getPassword(), bean.getEmail());
			res.setReturnObject(account);
		} catch (NicknameAlreadyBeenRegisteredException e) {
			// TODO Auto-generated catch block
			res.addError(JSONError.create("nickname", "用户名已经被注册"));
		} catch (EmailAlreadyBeenRegisteredException e) {
			// TODO Auto-generated catch block
			res.addError(JSONError.create("email", "email已经被注册"));
		}
		return res;
	}
	
	@RequestMapping(value="/signup", method=RequestMethod.GET)
	public String signUp(){
		return "sign_up";
	}

	@RequestMapping(value="/nicknameAvailable", method=RequestMethod.POST)
	public @ResponseBody JSONResponse nicknameAvailable(@RequestParam String nickname){
		Set<ConstraintViolation<SignupForm>> failures = validator.validateValue(SignupForm.class, "nickname", nickname);
		if (!failures.isEmpty()){
			return JSONResponse.invalid(failures);
		} 
		Account account = am.getAccountByName(nickname);
		if(account != null){
			return JSONResponse.error(JSONError.create("nickname", "用户名已经被注册"));
		}
		return JSONResponse.successed();
	}
	
	@RequestMapping(value="/passwordAvailable", method=RequestMethod.POST)
	public @ResponseBody JSONResponse passwordAvailable(@RequestParam String password){
		Set<ConstraintViolation<SignupForm>> failures = validator.validateValue(SignupForm.class, "password", password);
		if (!failures.isEmpty()){
			return JSONResponse.invalid(failures);
		} 
		return JSONResponse.successed();
	}
	
	@RequestMapping(value="/emailAvailable", method=RequestMethod.POST)
	public @ResponseBody JSONResponse emailAvailable(@RequestParam String email){
		Set<ConstraintViolation<SignupForm>> failures = validator.validateValue(SignupForm.class, "email", email);
		if (!failures.isEmpty()){
			return JSONResponse.invalid(failures);
		} 
		Account account = am.getAccountByEmail(email);
		if(account != null){
			return JSONResponse.errorMessage("email已经被注册");
		}
		return JSONResponse.successed();
	}
	
	//更改帐号密码和邮箱地址
	@RequestMapping(value="/account/{id}/password", method=RequestMethod.PUT)
	public @ResponseBody JSONResponse change(@RequestBody ChangePasswordForm bean, @PathVariable int id){
		Set<ConstraintViolation<ChangePasswordForm>> failures = validator.validate(bean);
		if(!failures.isEmpty()){
			return JSONResponse.invalid(failures);
		}
		try{
			//必须先改邮箱
			am.changeEmail(bean.getEmail(), bean.getOldPassword());	
			if(bean.getNewPassword() != null && bean.getNewPassword().length() > 0){
				am.changePassword(bean.getNewPassword(), bean.getOldPassword());	
			}
		} catch (InvalidPasswordException e) {
			// TODO Auto-generated catch block
			return JSONResponse.error(JSONError.create("oldPassword", "密码错误"));
		} catch (EmailAlreadyBeenRegisteredException e) {
			// TODO Auto-generated catch block
			return JSONResponse.error(JSONError.create("email", "邮箱已经存在"));
		}
		return JSONResponse.successed();
	}
	
	private static final String[] AllowSuffix = {"gif", "jpg", "jpeg", "png"};
	private static int MaxSize = 512*1024;	//512KB
	//上传头像
	@RequestMapping(value="/account/{id}/photo", method=RequestMethod.POST)
	public String uploadPhoto(@RequestParam("photo") MultipartFile mFile, @RequestHeader("Content-Length") int length, @PathVariable int id, Model model) throws IOException{
		String viewName = "upload_iframe";
		model.addAttribute("type", "uploadPhotoFailure");
		if(mFile.isEmpty()){
			model.addAttribute("message","上传头像失败");
			return viewName;
		}
		
		if(length > MaxSize){
			model.addAttribute("message","图片大小不能超过" + MaxSize/1024 + "KB");
			return viewName;
		}
		
		String originalFilename = mFile.getOriginalFilename();
		String suffix = getSuffix(originalFilename);
		int i = Arrays.binarySearch(AllowSuffix, suffix);
		if(i == -1){
			model.addAttribute("message","不能上传这种格式的图片");
			return viewName;
		}
		
		byte[] bytes = mFile.getBytes();
		if(bytes.length > MaxSize){
			model.addAttribute("message","图片大小不能超过" + MaxSize/1024 + "KB");
			return viewName;
		}
		
		//头像文件目录
		String photoDirectory = new StringBuffer().append(PathUtil.getAppDirectory().getPath()) 
											.append(File.separatorChar)
											.append("static")
											.append(File.separatorChar)
											.append("photo")
											.append(File.separatorChar)
											.toString();
		
		Account acc = am.getAccount(id);
		//临时头像文件路径
		String tempPhotoPath = new StringBuffer(photoDirectory).append("temp")
																.append(acc.getId())
																.append(".")
																.append(suffix)
																.toString();
		//临时头像文件
		File tempPhoto = new File(tempPhotoPath);
		tempPhoto.getParentFile().mkdirs();
		FileOutputStream fos = new FileOutputStream(tempPhoto);
		fos.write(bytes);
		fos.flush();
		fos.close();
		
		String destPhotoPath = new StringBuffer(photoDirectory).append(acc.getId())
																.append(".")
																.append(suffix)
																.toString();
		
		try {
			ImageResize.resize(tempPhoto, new File(destPhotoPath), 110, 160, true);
		} catch (UnsupportImageTypeException e) {
			// TODO Auto-generated catch block
			model.addAttribute("message","不支上传该图片，请确认您的图片是否能打开");
			return viewName;
		} catch (Exception e) {
			model.addAttribute("message","上传图片出错，可能与您上传的图片有关");
			return viewName;
		}
		
		String originalPhotoPath = new StringBuffer(photoDirectory).append(acc.getId())
																	.append("_original")
																	.append(".")
																	.append(suffix)
																	.toString();
	
		//临时头像文件替换原头像文件
		File originalPhoto = new File(originalPhotoPath);
		if(originalPhoto.exists()){
			originalPhoto.delete();
		}
		tempPhoto.renameTo(originalPhoto);
		//更新帐号头像信息
		String photoPath = format(destPhotoPath);
		acc.getExtInfo().setPhotoPath(photoPath);
		am.update(acc);
		
		model.addAttribute("type", "uploadPhotoSuccess");
		model.addAttribute("photoPath",acc.getExtInfo().getPhotoPath());
		return viewName;
	}
	
	/**
	 * 将本地文件系统地址转换为http uri地址
	 * @param filePath	本地文件系统地址
	 * @return	http uri地址
	 */
	private String format(String filePath){
		int index = filePath.lastIndexOf(File.separatorChar + "static");
		if(index == -1){
			throw new IllegalArgumentException("文件路径必须在static下");
		}
		String str = filePath.substring(index, filePath.length());
		return str.replace(File.separatorChar, '/');
	}
	
	/**
	 * 得到后缀名
	 * @param fileName
	 * @return 返回小写的后缀名，如果没有后缀名返回null
	 */
	private String getSuffix(String fileName){
		String suffix = null;
		int index = fileName.lastIndexOf('.');
		if(index != -1){
			suffix = fileName.substring(index+1, fileName.length());
		}
		if(suffix != null){
			suffix = suffix.toLowerCase();
		}
		return suffix;
	}
	
}
